﻿using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WanPiJie.Products
{
    public class CommodityService : ICommodityService
    {
        private MongoCollection<BsonDocument> dbSession;
        public CommodityService()
        {
            this.dbSession = MongoCollections.Wanpijie.GetCollection<BsonDocument>("pt_Commodity");
        }

        /// <summary>
        /// 添加商品数据至Mongo数据库
        /// </summary>
        /// <param name="commodity">商品对象</param>
        public void Insert(Commodity commodity)
        {
            this.dbSession.Insert(commodity.ToBsonDocument());
        }

        /// <summary>
        /// 根据孩子的生日获取相应的奶粉信息
        /// </summary>
        /// <param name="ageDays">生日信息</param>
        /// <param name="pageIndex">页代码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public List<Commodity> GetMilkByBirthday(int ageDays, Int32 pageIndex, Int32 pageSize)
        {
            var month = ageDays / 30;
            return this.QueryCommodities(Query.And(Query.EQ("CatalogId", (long)Category.Milk), Query.LTE("MinAge", month), Query.GTE("MaxAge", month)), pageIndex, pageSize);
        }

        /// <summary>
        /// 根据孩子的生日获取相应的奶嘴信息
        /// </summary>
        /// <param name="birthday">生日信息</param>
        /// <param name="pageIndex">页代码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public List<Commodity> GetNippleByBirthday(int ageDays, Int32 pageIndex, Int32 pageSize)
        {
            var month = ageDays / 30;
            return this.QueryCommodities(Query.And(Query.EQ("CatalogId", (long)Category.Nipple), Query.LTE("MinAge", month), Query.GTE("MaxAge", month)), pageIndex, pageSize);
        }

        /// <summary>
        /// 根据体重获取纸尿裤信息
        /// </summary>
        /// <param name="weight">体重</param>
        /// <param name="gender">性别</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public List<Commodity> GetDiapersByWeight(float weight, string gender, Int32 pageIndex, Int32 pageSize)
        {
            gender = gender.Equals("f") ? "女宝宝" : "男宝宝";
            return this.QueryCommodities(Query.And(Query.EQ("CatalogId", (long)Category.Diapers),
                Query.Or(Query.EQ("Attributes.29", gender), Query.EQ("Attributes.29", "通用")), Query.LTE("MinWeight", weight), Query.GTE("MaxWeight", weight)), pageIndex, pageSize);
        }

        /// <summary>
        /// 获取奶瓶信息
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns>指定页码的奶瓶信息</returns>
        public List<Commodity> GetMilkBottle(Int32 pageIndex, Int32 pageSize)
        {
            return this.QueryCommodities(Query.EQ("CatalogId", (long)Category.MilkBottle), pageIndex, pageSize);
        }


        /// <summary>
        /// 商品信息匹配
        /// </summary>
        /// <param name="weight">体重（千克）</param>
        /// <param name="birthday">生日</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public List<Commodity> GetCommodities(float weight, int ageDays, string gender, Int32 pageIndex, Int32 pageSize)
        {
            var month = ageDays / 30;
            var query = Query.And(Query.EQ("CatalogId", (long)Category.Diapers), Query.LTE("MinWeight", weight), Query.GTE("MaxWeight", weight));
            query = Query.Or(Query.EQ("CatalogId", (long)Category.MilkBottle), query);
            query = Query.Or(Query.And(Query.EQ("CatalogId", (long)Category.Nipple), Query.LTE("MinAge", month), Query.GTE("MaxAge", month)), query);
            query = Query.Or(Query.And(Query.EQ("CatalogId", (long)Category.Milk), Query.LTE("MinAge", month), Query.GTE("MaxAge", month)), query);
            return this.QueryCommodities(query, pageIndex, pageSize);
        }

        /// <summary>
        /// 分页获取商品信息
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns>指定页码，指定数量的商品信息</returns>
        public List<Commodity> GetCommodities(int pageIndex, int pageSize)
        {
            var query = Query.Or(Query.EQ("CatalogId", (long)Category.MilkBottle)
                , Query.EQ("CatalogId", (long)Category.Diapers)
                , Query.EQ("CatalogId", (long)Category.Milk)
                , Query.EQ("CatalogId", (long)Category.Nipple));
            return this.QueryCommodities(query, pageIndex, pageSize);
        }

        /// <summary>
        ///跳过指定的记录分页获取商品信息
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns>指定页码，指定数量的商品信息</returns>
        public List<Commodity> GetCommodities(int skip, int pageIndex, int pageSize)
        {
            var query = Query.Or(Query.EQ("CatalogId", (long)Category.MilkBottle)
    , Query.EQ("CatalogId", (long)Category.Diapers)
    , Query.EQ("CatalogId", (long)Category.Milk)
    , Query.EQ("CatalogId", (long)Category.Nipple));
            return this.QueryCommodities(query, skip, pageIndex, pageSize);
        }

        /// <summary>
        /// 根据指定的分类和条件获取商品信息
        /// </summary>
        /// <param name="catalogId">商品分类Id</param>
        /// <param name="weight">宝宝体重</param>
        /// <param name="birthday">宝宝生日</param>
        /// <param name="pageIndex">页码号</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public List<Commodity> GetCommodities(Int64 catalogId, float weight, int ageDays, string gender, Int32 pageIndex, Int32 pageSize)
        {
            if (catalogId == (long)Category.Milk)
            {
                return this.GetMilkByBirthday(ageDays, pageIndex, pageSize);
            }
            else if (catalogId == (long)Category.MilkBottle)
            {
                return this.GetMilkBottle(pageIndex, pageSize);
            }
            else if (catalogId == (long)Category.Diapers)
            {
                return this.GetDiapersByWeight(weight, gender, pageIndex, pageSize);
            }
            else if (catalogId == (long)Category.Nipple)
            {
                return this.GetNippleByBirthday(ageDays, pageIndex, pageSize);
            }
            else
            {
                return new List<Commodity>();
            }
        }

        /// <summary>
        ///分页 获取指定类目的所有商品
        /// </summary>
        /// <param name="catalogId">类目Id</param>
        /// <param name="pageIndex">页面号</param>
        /// <param name="pageSize">页面大小</param>
        /// <returns>返回指定类目的商品</returns>
        public List<Commodity> GetCommodities(Int64 catalogId, Int32 pageIndex, Int32 pageSize)
        {
            return this.QueryCommodities(Query.EQ("CatalogId", catalogId), pageIndex, pageSize);
        }

        /// <summary>
        /// 根据所属产品去获取相应的商品信息
        /// </summary>
        /// <param name="productId">产品Id</param>
        /// <param name="pageIndex">当前页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
       public List<Commodity> GetCommoditiesByProduct(Int64 productId, Int32 pageIndex, Int32 pageSize)
        {
            return this.QueryCommodities(Query.EQ("ProductId", productId), pageIndex, pageSize);
        }

        /// <summary>
        ///跳过指定的记录分页获取指定类目的所有商品
        /// </summary>
        /// <param name="catalogId">类目Id</param>
        /// <param name="pageIndex">页面号</param>
        /// <param name="pageSize">页面大小</param>
        /// <returns>返回指定类目的商品</returns>
        public List<Commodity> GetCommodities(Int64 catalogId, Int32 skip, Int32 pageIndex, Int32 pageSize)
        {
            return this.QueryCommodities(Query.EQ("CatalogId", catalogId), skip, pageIndex, pageSize);
        }

        /// <summary>
        /// MongoDB中是否存在指定的商品
        /// </summary>
        /// <param name="catalogId">商品类目Id</param>
        /// <param name="serialNumber">商品编号</param>
        /// <returns>BsonDocument：存在；NULL：不存在</returns>
        public BsonDocument HasCommodity(Int64 serialNumber)
        {
            return this.GetCommodity(Query.EQ("_id", serialNumber));
        }

        /// <summary>
        /// 获取单个销售信息
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <returns>单个产品的Bson对象</returns>
        private BsonDocument GetCommodity(IMongoQuery query)
        {
            return this.dbSession.FindOne(query);
        }

        /// <summary>
        /// 根据商品编号获取单个商品
        /// </summary>
        /// <param name="serialNumber">商品编号</param>
        /// <returns></returns>
        public Commodity GetCommodity(Int64 serialNumber)
        {
            return this.GetCommodity(Query.EQ("_id", serialNumber)).ToCommodity();
        }

        /// <summary>
        /// 获取指定商品的关联商品
        /// </summary>
        /// <param name="commodity">指定的商品对象</param>
        /// <returns></returns>
        public List<Commodity> GetRelatedCommodities(Commodity commodity, Int32 pageIndex, Int32 pageSize)
        {
            int i = 0;
            IMongoQuery[] equals = new QueryDocument[commodity.Attributes.Count + 1];
            equals[0] = Query.EQ("CatalogId", commodity.CatalogId);
            foreach (long key in commodity.Attributes.Keys)
            {
                equals[++i] = Query.EQ(string.Concat("Attributes.", key.ToString()), commodity.Attributes[key]);
            }
            return this.QueryCommodities(Query.And(Query.Or(equals), Query.NE("_id", commodity.SerialNumber)), pageIndex, pageSize);
        }

        /// <summary>
        /// 按照条件批量获取商品信息
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <param name="skip">页面</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        private List<Commodity> QueryCommodities(IMongoQuery query, Int32 pageIndex, Int32 pageSize)
        {
            return this.GetCommodities(query, (pageIndex - 1) * pageSize, pageSize);
        }

        /// <summary>
        /// 跳过指定的行数获取商品信息
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <param name="skip">提过指定的记录数量</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页面大小</param>
        /// <returns></returns>
        private List<Commodity> QueryCommodities(IMongoQuery query, int skip, Int32 pageIndex, Int32 pageSize)
        {
            return this.GetCommodities(query, skip + (pageIndex - 1) * pageSize, pageSize);
        }

        /// <summary>
        /// 跳过指定的行数获取商品信息
        /// </summary>
        /// <param name="query">获取商品信息的条件</param>
        /// <param name="skip">跳过的记录数</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        private List<Commodity> GetCommodities(IMongoQuery query, int skip, Int32 pageSize)
        {
            List<Commodity> commodities = new List<Commodity>();
            MongoCursor<BsonDocument> bsonDocuments = this.dbSession.Find(query).SetSortOrder(SortBy.Descending("Volume")).SetSkip(skip).SetLimit(pageSize);
            foreach (var bsonDocument in bsonDocuments)
            {
                commodities.Add(bsonDocument.ToCommodity());
            }
            return commodities;
        }

        /// <summary>
        /// 更新商品数据至Mongo数据库
        /// </summary>
        /// <param name="commodity">商品对象</param>
        public void Update(Commodity commodity)
        {
            var query = Query.And(Query.EQ("_id", commodity.SerialNumber),
                    Query.EQ("CatalogId", commodity.CatalogId));
            var update = new UpdateDocument { 
						{ "$set", new BsonDocument(){
						{"Price",commodity.Price.ToString()},
						{"Title",commodity.Title},
						{"ProductId",commodity.ProductId},
						{"MaxAge",commodity.MaxAge},
						{"MinAge",commodity.MinAge},
						{"Url",commodity.Url},
						{"Location",commodity.Location},
						{"ShopUrl",commodity.ShopUrl},
						{"SellerCreditScore",commodity.SellerCreditScore},
						{"SellerNick",commodity.SellerNick},
						{"Picture",commodity.Picture},
						{"MaxWeight",commodity.MaxWeight},
						{"MinWeight",commodity.MinWeight},
						{"Volume",commodity.Volume},
						{"Attributes", ClassExtension.ConvertAttributesToBson(commodity)},
						{"UpdateTime",DateTime.Now}
							}
						}
				};
            this.dbSession.Update(query, update);
        }
    }
}
